<?php
declare(strict_types=1);
namespace App\Dao;

use App\Exception\BusinessException;
use App\Model\Coupon;
use App\Model\CouponBatch;
use App\Utils\ServerUtil;
use App\Model\CouponLog;
use Hyperf\DbConnection\Db;
use App\Model\CouponStatistics;
use App\Constants\ErrorCode;
class CouponDao {

    use DaoTrait;
    
    public function __construct()
    {
        $this->driver=__CLASS__;    
    }

    /**
     * 查询
     * @param $where
     * @param string[] $columns
     * @return array
     */
    public function findByWhere($where, $columns=['*']){
        return Coupon::query()->where($where)->first($columns)->toArray();
    }


    /**
     * 查询优惠劵
     * @param $where
     * @param string[] $columns
     * @return \Hyperf\Database\Model\Builder|\Hyperf\Database\Model\Model|\Hyperf\Database\Query\Builder|object|null
     */
    public function findCouponByWhere($where, $columns=['coupon.id', 'coupon.unique_num', 'coupon.status', 'cb.amount', 'cb.status as batch_status', 'start_time', 'end_time']){
        return Coupon::query()->leftJoin('coupon_batch as cb', 'coupon.batch_id', '=', 'cb.id')->where($where)->first($columns);
    }

    /**
     * 更新
     * @param $where
     * @param $updateArray
     * @return int
     */
    public function update($where, $updateArray){
        return Coupon::query()->where($where)->update($updateArray);
    }

    //获取最大id
    public function getMaxId(){
        return Coupon::orderBy('id', 'desc')->value('id') ?: 1;
    }

    /**
     * 根据分页与条件查询数据
     * @Author czm
     * @DateTime 2020-05-26
     * @param array $map
     * @param array $page
     * @param array $fields
     * @return void
     */
    public function pageByWhere($map = [], $page = [], $fields = [], $scope = [])
    {
        $model = Coupon::query();
        if (!empty($fields)) {
            $model->select($fields);
        }
        $model = $model->when(!empty($map), function ($query) use ($map) {
            $query->where($map);
        });
        $count = $model->count();
        $data = $model->orderBy('id', 'desc')
                ->paginate(intval($page['pageSize']),['*'],'page',$page['page'])->each(function ($coupon) {
                    $coupon->append(['status_mapping']);
                })->toArray();
        return compact('count', 'data');
    }

    /**
     * 根据条件获取关联批次的红包信息
     * @Author czm
     * @DateTime 2020-05-28
     * @param array $map
     * @return void
     */
    public function firstWithBatchByWhere($map=[])
    {
        return Coupon::with('couponBatch')->when(!empty($map), function ($query) use ($map) {
            $query->where($map);
        })->first();
    }

    //根据openid判断是否有可用红包
    public function isHasCoupon($openid)
    {
        $ids=Coupon::where('openid',$openid)
        ->where('status',1)
        ->pluck('batch_id');
        $map=[
            ['status',1],
            ['start_time',"<",time()],
            ['end_time',">",time()]
        ];
        if($ids&&CouponBatch::whereIn('id',$ids)->where($map)->count()){
            return true;
        }else{
            return false;
        }
    }


     /**
     * 根据用户openid获取优惠券列表信息
     * @Author czm
     * @DateTime 2020-04-21
     * @param [type] $openid
     * @param [type] $flag 1 查询所有  2 查询可用
     * @return array|null
     */
    public function getUserCoupon($openid,$flag=1){
        if($flag==1){
            $map=[
                ['id',"!=",""]
            ];
        }else if($flag==2){
            $map=[
                ['status',1],
                ['start_time',"<",time()],
                ['end_time',">",time()]
            ];
        }

        $data=Coupon::where('openid',$openid)
        ->when($flag==2,function($query){
            //筛选可用
            $query->where('status',1);
        })
        ->with(['couponBatch'=>function($query)use($map){
            $query->where($map)->select("id","name","condition_amount","type","start_time","end_time","amount","status");
        }])
        ->get()->filter(function($value){
            if(!empty($value->couponBatch)){
                $value->couponBatch->append(['type_mapping']);
                $now=time();
                $status= $value->status;
                if($now<$value->couponBatch->start_time){
                    $status=5;
                }
                //过期标记
                if($now>$value->couponBatch->end_time&& $status==1){
                    $status=3;
                }
                $value->forceFill([
                    'name'=>$value->couponBatch->name,
                    'amount'=>$value->couponBatch->amount,
                    'type'=>$value->couponBatch->type,
                    'type_mapping'=>$value->couponBatch->type_mapping,
                    'condition_amount'=>$value->couponBatch->condition_amount,
                    'start_time'=>$value->couponBatch->start_time?date("Y-m-d H:i:s",$value->couponBatch->start_time):"",
                    'end_time'=>$value->couponBatch->end_time?date("Y-m-d H:i:s",$value->couponBatch->end_time):"",
                    'get_time'=>$value->get_time?date("Y-m-d H:i:s",$value->get_time):"",
                    'use_time'=>$value->use_time?date("Y-m-d H:i:s",$value->use_time):"",
                    'share_time'=>$value->share_time?date("Y-m-d H:i:s",$value->share_time):"",
                    'status'=>$status
                ])->append(['status_mapping'])->makeHidden('couponBatch');
                return true;
            }else{
                return false;
            }
        })->toArray();
        $data=array_values($data);
        // status 0未领取 1 未使用 2已使用 3已过期 4已禁用 5未生效
        return $data;
    }

    /**
     * status 0未领取 1 未使用 2已使用 3已过期 4已禁用 5未生效
     * @Author czm
     * @DateTime 2020-04-22
     * @param [type] $openid  openid
     * @param [type] $coupon_id 优惠券id
     * @param [type] $flag 1不限制状态 2限制可用状态 
     * @return array
     */
    public function getCouponByCondition($openid,$coupon_id,$flag=1){
        $map=[
            ['id',$coupon_id],
            ['openid',$openid]
        ];
        $value=Coupon::where($map)
        ->with(['couponBatch'=>function($query){
            $query->select("id","name","condition_amount","type","start_time","end_time","amount","status");
        }])
        ->first();
        if(!empty($value->couponBatch)){
            $value->couponBatch->append(['type_mapping']);
            $now=time();
            $status= $value->status;
          
            if($now<$value->couponBatch->start_time){
                $status=5;
            }
            if($now>$value->couponBatch->end_time&& $status==1){
                $status=3;
            }

            if($flag==2&&$status!=1){
                throw new BusinessException(ERRORCODE::ERR_BUESSUS,'优惠券非可用状态');
            }

            if($flag==2&&$status==5){
                throw new BusinessException(ERRORCODE::ERR_BUESSUS,'该优惠券没到使用时间');
            }

            if($flag==2&&$status==3){
                throw new BusinessException(ERRORCODE::ERR_BUESSUS,'该优惠券已过期');

            }

            if($flag==2&&$value->couponBatch->status!=1){
                throw new BusinessException(ERRORCODE::ERR_BUESSUS,'该优惠券批次不可用');
            }

            $value->forceFill([
                'name'=>$value->couponBatch->name,
                'amount'=>$value->couponBatch->amount,
                'type'=>$value->couponBatch->type,
                'type_mapping'=>$value->couponBatch->type_mapping,
                'condition_amount'=>$value->couponBatch->condition_amount,
                'start_time'=>date("Y-m-d H:i:s",$value->couponBatch->start_time),
                'end_time'=>date("Y-m-d H:i:s",$value->couponBatch->end_time),
                'get_time'=>$value->get_time?date("Y-m-d H:i:s",$value->get_time):"",
                'use_time'=>$value->use_time?date("Y-m-d H:i:s",$value->use_time):"",
                'share_time'=>$value->share_time?date("Y-m-d H:i:s",$value->share_time):"",
                'status'=>$status
            ])->append(['status_mapping'])->makeHidden('couponBatch')->toArray();
            return ['code'=>ErrorCode::SUCCESS,'msg'=>'获取成功','data'=>$value];
        }else{
            throw new BusinessException(ERRORCODE::ERR_BUESSUS,'获取优惠券信息失败！');
        }

    }


    /**
     * status 0未领取 1 未使用 2已使用 3已过期 4已禁用 5未生效
     * @Author czm
     * @DateTime 2020-04-23
     * @param [type] $openid
     * @param [type] $coupon_id
     * @param integer $flag 1标记使用 2领取优惠券 3恢复优惠券
     * @param string $order_no 订单号
     * @param integer $type_explain 
     * @return array
     */
    public function updateCoupon($openid,$coupon_id,$flag=1,$order_no='',$type_explain=0){
        $value=Coupon::with('couponBatch')->find($coupon_id);
        if(!empty($value)){
            Db::beginTransaction();
            try{ 
                $now=time();                    
                switch($flag){
                    case 1:
                        // if($value->openid!=$openid) return ['code'=>601,'msg'=>'该优惠券用户不可用'];
                        // if($value->status!=1) return ['code'=>602,'msg'=>'优惠券非可用状态'];
                        if($type_explain==5){
                            $value->type=1;
                        }   

                        if($type_explain==7){
                            $value->type=2;
                        }
                        
                        $value->status=2;
                        $value->use_time=$now;
                        $value->last_time=$now;
                        $value->save();
                        //日志记录
                        $insetArr=[
                                'openid'=>$openid,
                                'coupon_id'=> $coupon_id,
                                'unique_num'=>$value->unique_num,
                                'order_no'=>$order_no,
                                'type'=>2,
                                'type_explain'=>$type_explain,
                                'amount'=>$value->couponBatch->amount,
                                'add_time'=>time(),
                                'update_time'=>time(),
                                'start_time'=>$value->couponBatch->start_time,
                                'end_time'=>$value->couponBatch->end_time,   
                        ];
                        $msg='优惠券已使用';
                    break;
                    case 2:
                        // if($value->status!=0) return ['code'=>601,'msg'=>'优惠券非领取状态'];
                        $value->status=1;
                        $value->get_time=$now;
                        $value->last_time=$now;
                        $value->openid=$openid;
                        $value->save();
                        //日志记录
                        $insetArr=[
                            'openid'=>$openid,
                            'coupon_id'=> $coupon_id,
                            'unique_num'=>$value->unique_num,
                            'order_no'=>$order_no,
                            'type'=>1,
                            'type_explain'=>$type_explain,
                            'amount'=>$value->couponBatch->amount,
                            'add_time'=>time(),
                            'update_time'=>time(),
                            'start_time'=>$value->couponBatch->start_time,
                            'end_time'=>$value->couponBatch->end_time,   
                        ];
                        $msg='优惠券已领取';
                    break;
                    case 3:
                        // if($value->openid!=$openid) return ['code'=>601,'msg'=>'该优惠券用户不可用'];
                        $value->status=1;
                        $value->type=0;
                        $value->use_time=0;
                        $value->last_time=$now;
                        $value->save();
                        //日志记录
                        $insetArr=[
                            'openid'=>$openid,
                            'coupon_id'=> $coupon_id,
                            'unique_num'=>$value->unique_num,
                            'order_no'=>$order_no,
                            'type'=>1,
                            'type_explain'=>$type_explain,
                            'amount'=>$value->couponBatch->amount,
                            'add_time'=>time(),
                            'update_time'=>time(),
                            'start_time'=>$value->couponBatch->start_time,
                            'end_time'=>$value->couponBatch->end_time,   
                        ];
                        $msg='优惠券已退还';
                    break;
                }
                CouponLog::insert($insetArr);
                Db::commit();
                return ['code'=>ErrorCode::SUCCESS,'msg'=>$msg];

            }catch(\Throwable $t){
                Db::rollback();
                ServerUtil::info('优惠券处理逻辑层异常',['param'=>func_get_args(),'res'=>$t->getMessage()]);
                throw new BusinessException(ERRORCODE::ERR_BUESSUS,'优惠券处理逻辑层异常');

            }
        }else{
            throw new BusinessException(ERRORCODE::ERR_BUESSUS,'获取优惠券信息失败！');
        }

    }

    /**
     * 统计红包情况
     * @Author czm
     * @DateTime 2020-04-30
     * @return void
     */
    public function addstatistics()
    {
      
        $date=date('Y/m/d',time()-3600*24);
        $info=CouponStatistics::orderBy('add_time','desc')->first();
        if($info&&$info['date']==$date){
            return ['code'=>ERRORCODE::ERR_BUESSUS,'msg'=>'已存在记录'];
        }
        if(ServerUtil::getLock('addstatistics',86500)){
            $startTime=strtotime(strval(date("Y-m-d")));
            $map=[
                ['coupon.add_time','<',$startTime]
            ];
            $sql=Coupon::leftJoin('coupon_batch','coupon_batch.id','=','coupon.batch_id');
            //筛选统计数据 因为要追踪历史数据缘故没办法做分批查询  后期可以把券 情况值记录起来使用时候自动修正数字方便统计直接获取数据
            // $use_amount=$data->filter(function($value){return $value->status==1;})->sum('amount');
            $useMap=$map;
            $notUseMap=$map;
            $expireMap=$map;

            $sql1=clone $sql;
            $sql2=clone $sql;
            $sql3=clone $sql;
            $sql4=clone $sql;

            array_push($useMap,['coupon.status','=',2]);
            $phone_use_amount=$sql->where($useMap)->where('coupon.type',1)->sum('amount');
            $phone_use_num=$sql->where($useMap)->where('coupon.type',1)->count();

            $oil_use_amount=$sql1->where($useMap)->where('coupon.type',2)->sum('amount');
            $oil_use_num=$sql1->where($useMap)->where('coupon.type',2)->count();

            $use_amount=$sql->where($useMap)->sum('amount');
            $use_num=$sql->where($useMap)->count();


            array_push($notUseMap,['coupon.status','!=',2]);
            $not_use_amount=$sql2->where($notUseMap)->sum('amount');
            $not_use_num=$sql2->where($notUseMap)->count();
           
            array_push($expireMap,['coupon_batch.end_time','<',$startTime],['coupon.status','!=',2]);
            $expire_amount=$sql3->where($expireMap)->sum('amount');
            $expire_num=$sql3->where($expireMap)->count();

           

            CouponStatistics::create(compact('date','use_amount','use_num','phone_use_amount','phone_use_num','oil_use_amount','oil_use_num','not_use_amount','not_use_num','expire_amount','expire_num'));
            // * status 0未领取 1 未使用 2已使用 3已过期 4已禁用 5未生效
            ServerUtil::delLock('addstatistics');
            return ['code'=>ErrorCode::SUCCESS,'msg'=>'记录成功'];
        }else{
            ServerUtil::info('统计红包情况日志存在锁异常！',['param'=>$date,'res'=>'redis锁未释放']);
            throw new BusinessException(ERRORCODE::ERR_BUESSUS,'统计红包情况日志存在锁异常！');
        }
   
    }

}